(function () {
	"use strict";

	let ill = {};

	// viewports etc

	ill.elementIsVisible = function(el) {
		let rect = el.getBoundingClientRect(),
			viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
		return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
	};

	ill.ensureElementInView = function(el) {
		if (!ill.elementIsVisible(el)) {
			el.scrollIntoView({behavior: "smooth"});
		}
	};

	// events

	ill.unselectAllRecords = function() {
		[].forEach.call(document.querySelectorAll(".illustrated .record.selected, .illustrated .calculation.selected"),
		function(el) {
			el.classList.remove("selected");
		});
	};

	ill.toggleRecord = function(element, event) {
		let selected = element.classList.contains("selected");
		ill.unselectAllRecords();
		if (!selected) {
			element.classList.add("selected");
		} else {
			ill.closeAllCode();
		}
		ill.cancel(event);
		ill.ensureElementInView(element);
	};

	ill.selectRecord = function(element, event) {
		ill.unselectAllRecords();
		element.classList.add("selected");
		ill.cancel(event);
		ill.ensureElementInView(element);
	};

	ill.showCode = function(element, event) {
		element.parentNode.classList.add("show");
		ill.cancel(event);
	};

	ill.closeAllCode = function() {
		[].forEach.call(document.querySelectorAll("codesample.show"), function(el) {
			el.classList.remove("show");
		});
	};

	ill.toggleAnnotate = function(el) {
		el.classList.toggle("annotate");
	};

	ill.cancel = function(event) {
		if (event) { event.stopPropagation(); }
	};

	// injections

	ill.addShowCode = function(el) {
		el.innerHTML = document.getElementById("showCodeTmpl").innerHTML + el.innerHTML;
	};

	ill.addToggleAnnotations = function(record) {
		let expl = record.querySelector(".rec-explanation"),
			copy = document.getElementById("annotateTmpl").cloneNode(true);
		expl.insertAdjacentElement("afterend", copy);
	};

	ill.injectLabels = function() {
		let els = document.querySelectorAll(".string > .explanation, .decryption > .explanation");
		[].forEach.call(els, function(expl) {
			let label = expl.parentNode.querySelector(".label"),
				h4 = document.createElement("h4");
			h4.appendChild(document.createTextNode(label.textContent));
			expl.insertAdjacentElement("afterbegin", h4);
		});
	};

	ill.injectEmbedArrows = function() {
		let els = document.querySelectorAll(".record.embedded");
		[].forEach.call(els, function(r) {
			let arrow = document.createElement("div"),
				parent = r.parentNode;
			arrow.setAttribute("class", "embed-arrow");
			arrow.innerText = "➥";
			parent.insertBefore(arrow, r);
		});
	};

	ill.printMode = function() {
		// add printmode css
		let inject = document.createElement("link");
		inject.setAttribute("rel", "stylesheet");
		inject.setAttribute("href", "printmode.css");
		document.head.appendChild(inject);
		// open everything up
		[].forEach.call(document.querySelectorAll(".record, .calculation"), function(el){
			el.classList.add("selected");
			el.classList.add("annotate");
		});
		[].forEach.call(document.querySelectorAll("processblock"), function(el){
			el.classList.add("notrunc");
		});
		[].forEach.call(document.querySelectorAll("codesample"), function(el){
			el.classList.add("show");
		});
		[].forEach.call(document.querySelectorAll("*"), function(el) {
			el.onclick = null;
		});
	};


	window.onload = function() {
		[].forEach.call(document.querySelectorAll(".record, .calculation"), function(el) {
			el.onclick = function(event) {
				if (el === event.target && event.offsetY < 60) {
					ill.toggleRecord(el, event);
				} else {
					ill.selectRecord(el, event);
				}
			};
		});
		[].forEach.call(document.querySelectorAll(".rec-label"), function(el) {
			el.onclick = function(event) {
				ill.toggleRecord(el.parentNode, event);
			};
		});
		[].forEach.call(document.querySelectorAll("processblock"), function(el) {
			el.onclick = function(event) {
				el.classList.add("clicked");
				ill.cancel(event);
			};
		});
		[].forEach.call(document.querySelectorAll(".record"), function(el) {
			ill.addToggleAnnotations(el);
		});
		[].forEach.call(document.querySelectorAll("codesample"), function(el) {
			ill.addShowCode(el);
		});
		ill.injectLabels();
		ill.injectEmbedArrows();
	};

	window.onkeyup = function(e) {
		let els;
		if (e.keyCode === 27) {
			els = document.querySelectorAll(".record.annotate");
			if (els.length) {
				[].forEach.call(els, function(rec) { rec.classList.remove("annotate"); });
			} else {
				ill.unselectAllRecords();
			}
		}
	};

	window.ill = ill;
})();
